using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.IO;
using System.Runtime.InteropServices;

namespace MapAndCharacter_Filip
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game : Microsoft.Xna.Framework.Game
    {
        const int WINDOW_WIDTH = 800;
        const int WINDOW_HEIGHT = 600;
        GraphicsDeviceManager graphics;
        public SpriteBatch spriteBatch;

        MouseState lastMouseState = Mouse.GetState();
        Viewport viewport;
        //MovableSprite character;
        Texture2D map;
        Rectangle mapRectangle;
        public Dictionary<int, MovableSprite> characters;
        Random r;
        SpriteFont font;
        Color[] colors;
        //BroadcastClient broadcastClient;

        public Game()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            graphics.PreferredBackBufferHeight = WINDOW_HEIGHT;
            graphics.PreferredBackBufferWidth = WINDOW_WIDTH;
            graphics.IsFullScreen = false;
            IsMouseVisible = true;

            characters = new Dictionary<int, MovableSprite>();
            colors = new Color[] { Color.Blue, Color.Yellow, Color.Orange, Color.Green, Color.Purple };
            Mouse.WindowHandle = Window.Handle;
            r = new Random();
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            System.Drawing.Point p = new System.Drawing.Point(10, 10);// or wherever you want
            System.Windows.Forms.Control c = System.Windows.Forms.Control.FromHandle(this.Window.Handle);
            c.Location = p;
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // Get the screen dimensions
            viewport = GraphicsDevice.Viewport;
            if (!GameState.IsHost)
            {
                MovableSprite character = new MovableSprite(this.Content, this.spriteBatch);
                character.Load("TempCharacter");
                character.Position = new Vector2(20, 20);
                characters.Add(GameState.client.ID, character);
            }

            //map = new Sprite(this.Content, this.spriteBatch);
            //if (GameState.IsNewMap)
            //{

            //    using (FileStream fileStream = new FileStream(GameState.mapImage, FileMode.Open))
            //    {
            //        map = Texture2D.FromStream(GraphicsDevice, fileStream);
            //    }
                
            //}
            //else
            //{
                map = Content.Load<Texture2D>("TempMap");
                //map.Load("TempMap", WINDOW_WIDTH, WINDOW_HEIGHT);
            //}
            mapRectangle = new Rectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
            
            //map.Position = new Vector2(10, 10);
            font = Content.Load<SpriteFont>("text");
            //broadcastClient = new BroadcastClient();
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                Exit();

            int x = 0, y = 0;

            // check if any messages received and resolve them
            MapMessage message = NetworkManager.GetMapMessage();
            if (message.userID != -1)
            {
                if (!characters.ContainsKey(message.userID))
                {
                    MovableSprite character = new MovableSprite(this.Content, this.spriteBatch);
                    character.Load("TempCharacter");
                    character.Position = new Vector2(20, 20);
                    character.Color = colors[r.Next(0, colors.Length)];
                    characters.Add(message.userID, character);
                    characters[message.userID].MoveToPosition(new Vector2(message.x, message.y));
                }
                else
                    characters[message.userID].MoveToPosition(new Vector2(message.x, message.y));
            }

            // move our character
            if (GameState.IsHost)
            {
                if (GameState.hostChar != 75 && !characters[GameState.hostChar].IsMoving)
                {
                    var currentMouseState = Mouse.GetState();

                    if (lastMouseState.LeftButton == ButtonState.Pressed &&
                        currentMouseState.LeftButton == ButtonState.Released)
                    {
                        x = currentMouseState.X;
                        y = currentMouseState.Y;
                        //Console.WriteLine("Click location: (" + x + ", " + y + ")");

                        // Set the position to the current mouse location
                        if (0 < x && x < WINDOW_WIDTH && 0 < y && y < WINDOW_HEIGHT)
                        {
                            characters[GameState.hostChar].MoveToPosition(new Vector2(x, y));

                            NetworkManager.SendMapMessage(x, y, GameState.hostChar);
                        }
                    }

                    lastMouseState = currentMouseState;
                }
            }
            else if (!characters[GameState.client.ID].IsMoving)
            {
                var currentMouseState = Mouse.GetState();

                if (lastMouseState.LeftButton == ButtonState.Pressed &&
                    currentMouseState.LeftButton == ButtonState.Released)
                {
                    x = currentMouseState.X;
                    y = currentMouseState.Y;
                    //Console.WriteLine("Click location: (" + x + ", " + y + ")");

                    // Set the position to the current mouse location
                    if (0 < x && x < WINDOW_WIDTH && 0 < y && y < WINDOW_HEIGHT)
                    {
                        characters[GameState.client.ID].MoveToPosition(new Vector2(x, y));

                        NetworkManager.SendMapMessage(x, y, GameState.client.ID);
                    }
                }

                lastMouseState = currentMouseState;
            }
            foreach (KeyValuePair<int, MovableSprite> entry in characters)
            {
                entry.Value.Move();
            }

            if (GameState.IsNewMap)
            {

                using (FileStream fileStream = new FileStream(GameState.mapImage, FileMode.Open))
                {
                    map = Texture2D.FromStream(GraphicsDevice, fileStream);
                }
                GameState.IsNewMap = false;
                GameState.mapImage = "";
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            this.spriteBatch.Begin();
            spriteBatch.Draw(map, mapRectangle, Color.White);
            foreach (KeyValuePair<int, MovableSprite> entry in characters)
            {
                entry.Value.Draw();
            }
            //this.character.Draw();
            this.spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
